package com.vhall.component.plugin.common.filter;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.vhall.component.framework.common.bean.CommonRequest;
import com.vhall.component.framework.common.exception.BusinessException;
import com.vhall.component.framework.common.support.SecretKeyThreadLocal;
import com.vhall.component.framework.common.support.UserTicketVO;
import com.vhall.component.framework.common.utils.AesUtil;
import com.vhall.component.framework.common.utils.HttpServletUtils;
import com.vhall.component.framework.common.utils.JsonUtil;
import com.vhall.component.framework.common.utils.StringUtils;
import com.vhall.component.plugin.common.constant.RedisKey;
import com.vhall.component.plugin.common.exception.BizErrorCode;
import com.vhall.component.plugin.common.manager.CommonCacheManager;
import com.vhall.component.plugin.common.support.AdmToken;
import com.vhall.component.plugin.common.thrift.common.UserTicketWrapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashSet;
import java.util.Map;
import java.util.Objects;

/**
 * API-请求解密处理
 *
 * @author yuanzh
 */
@Slf4j
@RequiredArgsConstructor
public class EncryptionFilter extends OncePerRequestFilter {

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Autowired
    private CommonCacheManager commonCacheManager;

    public static final String ROOM_CONSOLE_CREATE = "/v4/room/console/create" ;
    public static final String ROOM_CONSOLE_UPDATE = "/v4/room/console/update" ;
    public static final String ROOM_DRAFT_URL = "/v4/room-draft/save-draft" ;
    public static final String SEND_MESSAGE_URL = "/v4/chat/send-message" ;
    public static final String ROOM_GOODS_ADD = "/v4/goods/console/guoxin/add/room-goods" ;
    /**
     * 不做返回结果包装的 url
     */
    private static final HashSet<String> NOT_HANDLE_URLS = new HashSet<>();
    static{
        NOT_HANDLE_URLS.add(ROOM_CONSOLE_CREATE);
        NOT_HANDLE_URLS.add(ROOM_CONSOLE_UPDATE);
        NOT_HANDLE_URLS.add(ROOM_DRAFT_URL);
        NOT_HANDLE_URLS.add(SEND_MESSAGE_URL);
        NOT_HANDLE_URLS.add(ROOM_GOODS_ADD);

    }

    @Override
    protected boolean shouldNotFilter(@NotNull HttpServletRequest request) {
        return false;
    }

    @SuppressWarnings("unchecked")
    @Override
    protected void doFilterInternal(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response,
                                    @NotNull FilterChain chain) throws ServletException, IOException {
        ParameterRequestWrapper requestWrapper = new ParameterRequestWrapper(request);
        String path = request.getRequestURI();
        if (StrUtil.isNotBlank(path) && StrUtil.contains(path,"//")) {
            path = path.replace("//","/");
        }
        // 若为json请求，解密处理
        if (HttpServletUtils.isJsonRequest(requestWrapper) && !NOT_HANDLE_URLS.contains(path)) {
            final String fixedSecretKey = "default_00000001";
            final String fixedSecretIv = "0000000000000000";
            String requestJsonData = IOUtils.toString(requestWrapper.getBody(), request.getCharacterEncoding());
            CommonRequest commonRequest = JsonUtil.objectFromJSONString(requestJsonData, CommonRequest.class);

            if (Objects.nonNull(commonRequest) && StringUtils.isNotEmpty(commonRequest.getRequestData())) {
                String requestEncryptData = commonRequest.getRequestData();
                String ticket = commonRequest.getTicket();

                String headerToken = request.getHeader("token");
                UserTicketWrapper userTicketWrapper;

                String secretKey = fixedSecretKey;
                String secretIv = fixedSecretIv;
                UserTicketVO userTicket = new UserTicketVO();
                if (StringUtils.isNotEmpty(headerToken) && StringUtils.isNotEmpty(ticket)) {

                    // 判断是否上送票据，若无票据
                    if (StringUtils.isEmpty(ticket)) {
                        throw new BusinessException(BizErrorCode.AUTH_ADM_TOKEN_INVALID);
                    }
                    userTicket.setTicket(ticket);
                    String token = redisTemplate.opsForValue().get(RedisKey.AUTH_TOKEN + headerToken);
                    if (org.apache.commons.lang3.StringUtils.isBlank(token)) {
                        throw new BusinessException(BizErrorCode.AUTH_ADM_TOKEN_INVALID);
                    }
                    AdmToken admToken = JsonUtil.objectFromJSONString(JSON.parse(token).toString(), AdmToken.class);
                    if (Objects.nonNull(admToken) && Objects.nonNull(admToken.getAdminId())) {
                        // 从缓存中获取用户票据及密钥
                        userTicketWrapper = commonCacheManager.getUserTicket(admToken.getAdminId().longValue());
                        if (validTicket(userTicketWrapper) && userTicketWrapper.getWebTicket().getC3().equals(ticket)) {
                            secretKey = userTicketWrapper.getWebTicket().getC3Key();
                            secretIv = userTicketWrapper.getWebTicket().getC3Iv();
                        }
                    }
                }
                userTicket.setSecretKey(secretKey);
                userTicket.setSecretIv(secretIv);
                SecretKeyThreadLocal.setTicket(userTicket);

                String requestDecryptData = AesUtil.decryptPKCS7(requestEncryptData, secretKey, secretIv);
                log.info("requestEncryptData={}, requestDecryptData={}", requestEncryptData, requestDecryptData);

                if (StringUtils.isNotEmpty(requestDecryptData)) {
                    Map<String, Object> extraParams = JSON.parseObject(requestDecryptData, Map.class);
                    requestWrapper.setResetParams(true);
                    requestWrapper.addParameters(extraParams);
                }
            }
        }
        try {
            // 继续过滤器
            chain.doFilter(requestWrapper, response);
        } catch (Exception ex) {
            // 异常执行，记录日志
            throw ex;
        } finally {
            SecretKeyThreadLocal.remove();
        }
    }

    /**
     * 校验票据
     *
     * @param userTicketWrapper 票据信息
     * @return 结果
     */
    public boolean validTicket(UserTicketWrapper userTicketWrapper) {
        return Objects.nonNull(userTicketWrapper) && userTicketWrapper.isSetWebTicket() && userTicketWrapper.getWebTicket()
                .isSetExpireTs()
                && userTicketWrapper.getWebTicket().getExpireTs() > System.currentTimeMillis() && userTicketWrapper.getWebTicket()
                .isSetC3()
                && userTicketWrapper.getWebTicket().isSetC2();
    }

}
